package edu.ntu.cloudroid.server;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;


import com.google.appengine.api.datastore.Key;

import edu.ntu.cloudroid.model.IDs;
import edu.ntu.cloudroid.model.data.AbstractData;
import edu.ntu.cloudroid.model.data.DetachedData;
import edu.ntu.cloudroid.model.friend.FriendInfo;
import edu.ntu.cloudroid.model.friend.GroupData;
import edu.ntu.cloudroid.model.friend.GroupInfo;
import edu.ntu.cloudroid.model.policy.AbstractPrivacyPreference;
import edu.ntu.cloudroid.model.policy.PolicyInfo;
import edu.ntu.cloudroid.model.profile.ProfileData;
import edu.ntu.cloudroid.model.profile.ProfileInfo;
import edu.ntu.cloudroid.server.backendservice.DataService;
import edu.ntu.cloudroid.server.backendservice.FriendService;
import edu.ntu.cloudroid.server.backendservice.GroupService;
import edu.ntu.cloudroid.server.backendservice.PolicyService;
import edu.ntu.cloudroid.server.backendservice.ProfileService;

/**
 * Helper class for uploading data to the store.
 * 
 */
public class Uploader {

	public static void uploadProfile(ProfileInfo profile) throws Exception {
		if (profile.getEmailAddress().startsWith("null")){
			UploadServlet.logger.info("Removing profile "+profile.getEmailAddress());
			ProfileService.deleteProfile(profile.getEmailAddress().split(" ")[1]);
			return;
		}
		ProfileData p = new ProfileData();
		p.setEmailAddress(profile.getEmailAddress());
		p.setDataId(profile.getDataType());
		p.setPolicyCombiningAlg(profile.getPolicyCombinationId());
		
		//if the profile already exist, delete it
		//ProfileService.deleteProfile(profile.getEmailAddress());
		
		long start = System.currentTimeMillis();
		ProfileService.addProfile(p);
		long end = System.currentTimeMillis();
		UploadServlet.logger.info("profile insert = "+(end-start));
	}
	
	public static void uploadPolicy(PolicyInfo policy) throws Exception{

		String[] row = policy.getPreferenceString();
		
		int privacyType = new Integer(row[1]).intValue();
		
		
		if (policy.getUserEmail().startsWith("null")){
			UploadServlet.logger.info("deleting policy for "+policy.getUserEmail()+" of type = "+privacyType);
			PolicyService.deleteAllPoliciesForUser(privacyType, policy
					.getUserEmail().split(" ")[1]);
			return;
		}
		ProfileData profile = ProfileService.getProfile(row[0]);
		AbstractPrivacyPreference app = (AbstractPrivacyPreference) PolicyService
				.getPolicyObject(privacyType);
		app.initialize(row);
		app.setUserName(policy.getUserEmail());
		
		//app.initializePreference(row);
		long start = System.currentTimeMillis();
		if (app.getAccessType()==AbstractPrivacyPreference.ISALL)
		   PolicyService.updateDefaultPolicy(profile, app, privacyType);
		else if (app.getAccessType()==AbstractPrivacyPreference.ISGROUP){
			String groupName = profile.getEmailAddress()+"_group_"+app.getAccessSubject();			
			PolicyService.updateGroupPolicy(profile, app, groupName, privacyType);
		}
		long end = System.currentTimeMillis();
		UploadServlet.logger.info("policy insert = "+(end-start));
	}
	
	public static void uploadFriend(FriendInfo friend) throws Exception{		
		UploadServlet.logger.info("uploading friend between "
				+ friend.getUser1() + " vs " + friend.getUser2());
		if (friend.getUser1().startsWith("null") && friend.getUser2().startsWith("null")){
			UploadServlet.logger.info("deleting all friends for user "+friend.getUser1());
			FriendService.deleteAllFriendsForUser(friend.getUser1().split(" ")[1]);
			return;
		}
		long start = System.currentTimeMillis();
		if (friend.getType() == FriendInfo.ADD) {			
			FriendService.addFriend(friend);
		} else if (friend.getType() == FriendInfo.REMOVE) {
			FriendService.removeFriend(friend.getUser1(), friend.getUser2());
			FriendService.removeFriend(friend.getUser2(), friend.getUser1());
			//then also remove from all groups
			for (GroupData g : GroupService.getGroupData(friend.getUser1(), friend.getUser2()))
				GroupService.deleteGroupMember(g, friend.getUser2());
			for (GroupData g : GroupService.getGroupData(friend.getUser2(), friend.getUser1()))
				GroupService.deleteGroupMember(g, friend.getUser1());
		}
		long end = System.currentTimeMillis();
		UploadServlet.logger.info("friend insert = "+(end-start));
	}
	
	public static void uploadGroup(GroupInfo group) throws Exception{
		if (group.getType() == GroupInfo.NEW)
			GroupService.addNewGroup(group);
		else if (group.getType() == GroupInfo.ADD)
			GroupService.addGroupMember(group.getOwnerName(), group.getGroupName(), group.getGroupMemberKeys());
		else if (group.getType() == GroupInfo.REMOVE){
			GroupService.deleteGroup(group.getOwnerName(), group.getGroupName());
		}
	}
	
	public static void uploadData(DetachedData data) throws Exception{
		AbstractData ad = data.toGAEData();
		if (ad.getName().startsWith("null")){
			UploadServlet.logger.info("deleting data from "+ad.getName());
			String user = ad.getName().split(" ")[1];
			DataService.removeDataFromUser(ad.getDataId(), user);
			return;
		}
		long start = System.currentTimeMillis();
		DataService.addData(ad);
		long end = System.currentTimeMillis();
		UploadServlet.logger.info("data insert = "+(end-start));
	}
	
	
	/**
	 * Add new users and their associated policies
	 */
	public static void uploadUsersAndPolicies(Logger logger,
			List<String[]> entries) {
		int i = 0;
		for (String[] row : entries) {
			i++;
			if (row.length <= 1)
				continue;
			try {

				ProfileData p = new ProfileData();				
				p.setEmailAddress(row[0]);
				p.setDataId(new Integer(row[1]).intValue());

				int privacyType = new Integer(row[2]).intValue();
				AbstractPrivacyPreference app = (AbstractPrivacyPreference) PolicyService
						.getPolicyObject(privacyType);
				app.initialize(row);
				//app.initializePreferce(row);

				ProfileService.addProfile(p);
				PolicyService.updateDefaultPolicy(p, app, privacyType);
			} catch (Exception e) {
				logger.log(Level.WARNING,
						"Runtime exception while processing data (row " + i
								+ "): " + e.getMessage());
				e.printStackTrace();
			}
		}
	}

	public static void uploadFriendRelations(Logger logger,
			List<String[]> entries) throws Exception {
		ProfileData p1, p2;
		for (String[] row : entries) {
			if (row.length <= 1)
				continue;
			// row: user1, user2
			p1 = ProfileService.getProfile(row[0] + "@gmail.com");
			p2 = ProfileService.getProfile(row[1] + "@gmail.com");
			FriendService.addFriend(new FriendInfo(p1.getEmailAddress(), p2.getEmailAddress(), FriendInfo.ADD));
		}

	}
		
	public static void uploadData(Logger logger, List<String[]> entries)
			throws Exception {	
		for (String[] row : entries) {
			if (row.length <= 1)
				continue;			
			AbstractData ad = (AbstractData) DataService
					.getAbstractDataObject(new Integer(row[0]).intValue());			
			AbstractData data = ad.initialize(row);
			DataService.addData(data);
		}
	}
	
	public static void uploadNames(Logger logger, List<String[]> entries) {

		List<String> names = new ArrayList<String>();
		for (String[] row : entries) {
			if (row.length == 1 && !row[0].trim().equals(""))
				names.add(row[0].trim());
		}
		//FixtureUtil.addUniqueNames(names);
	}
}
